﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.UI;
using Windows.UI.Core;
using Windows.UI.Xaml.Media;

namespace WinRTSock.Test
{
    public class TestPageViewModel : INotifyPropertyChanged
    {
        private WinRTSock_RuntimeComponents_Test.WinRTSockTests utility;
        private int totalTestCount;
        private int succeededTestCount;
        private int failedTestCount;
        private SolidColorBrush testSuiteResultIndicator;

        public int TotalTestCount
        {
            get { return this.totalTestCount; }
            set
            {
                if (this.totalTestCount == value)
                    return;
                this.totalTestCount = value;
                this.OnPropertyChanged("TotalTestCount");
            }
        }
        public int SucceededTestCount
        {
            get { return this.succeededTestCount; }
            set
            {
                if (this.succeededTestCount == value)
                    return;
                this.succeededTestCount = value;
                this.OnPropertyChanged("SucceededTestCount");
            }
        }
        public int FailedTestCount
        {
            get { return this.failedTestCount; }
            set
            {
                if (this.failedTestCount == value)
                    return;
                this.failedTestCount = value;
                this.OnPropertyChanged("FailedTestCount");
            }
        }
        public SolidColorBrush TestSuiteResultIndicator
        {
            get { return this.testSuiteResultIndicator; }
            set
            {
                if (this.testSuiteResultIndicator == value)
                    return;
                this.testSuiteResultIndicator = value;
                this.OnPropertyChanged("TestSuiteResultIndicator");
            }
        }

        public ObservableCollection<TestItemViewModel> Items { get; private set; }

        public TestPageViewModel(CoreDispatcher dispatcher)
        {
            this.Items = new ObservableCollection<TestItemViewModel>();

            this.Items.Add(TestItemViewModel.Create("SIP Connect", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.SIPConnectTest(); }, this.updateTotals));

            this.Items.Add(TestItemViewModel.Create("Create stream socket", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.CreateStreamSocketTest(); }, this.updateTotals));
            this.Items.Add(TestItemViewModel.Create("Create datagram socket", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.CreateDatagramSocketTest(); }, this.updateTotals));
            this.Items.Add(TestItemViewModel.Create("Create invalid socket", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.CreateInvalidSocketTest(); }, this.updateTotals));
            
            this.Items.Add(TestItemViewModel.Create("Initialize sockaddr with IPv4 address", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.SockAddrInfoInitWithIpv4Test(); }, this.updateTotals));
            this.Items.Add(TestItemViewModel.Create("Initialize sockaddr with IPv6 address", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.SockAddrInfoInitWithIpv6Test(); }, this.updateTotals));
            this.Items.Add(TestItemViewModel.Create("Initialize sockaddr with host name", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.SockAddrInfoInitWithHostNameTest(); }, this.updateTotals));
            
            this.Items.Add(TestItemViewModel.Create("Get family with IPv4 address", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.GetFamilyWithIpv4Test(); }, this.updateTotals));
            this.Items.Add(TestItemViewModel.Create("Get family with IPv6 address", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.GetFamilyWithIpv6Test(); }, this.updateTotals));
            this.Items.Add(TestItemViewModel.Create("Get family with host name", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.GetFamilyWithHostNameTest(); }, this.updateTotals));
            
            this.Items.Add(TestItemViewModel.Create("Connect stream socket with IPv4 address", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.ConnectStreamSocketWithIpv4Test(); }, this.updateTotals));
            this.Items.Add(TestItemViewModel.Create("Connect datagram socket with IPv4 address", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.ConnectDatagramSocketWithIpv4Test(); }, this.updateTotals));
            this.Items.Add(TestItemViewModel.Create("Connect stream socket with IPv6 address", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.ConnectStreamSocketWithIpv6Test(); }, this.updateTotals));
            this.Items.Add(TestItemViewModel.Create("Connect datagram socket with IPv6 address", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.ConnectDatagramSocketWithIpv6Test(); }, this.updateTotals));
            this.Items.Add(TestItemViewModel.Create("Connect stream socket with host name address", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.ConnectStreamSocketWithHostNameTest(); }, this.updateTotals));
            this.Items.Add(TestItemViewModel.Create("Connect datagram socket with host name address", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.ConnectDatagramSocketWithHostNameTest(); }, this.updateTotals));
            
            this.Items.Add(TestItemViewModel.Create("Get sock name for IPv4 address stream socket", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.GetSockNameWithIpv4StreamSocketTest(); }, this.updateTotals));
            this.Items.Add(TestItemViewModel.Create("Get sock name for IPv4 address datagram socket", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.GetSockNameWithIpv4DatagramSocketTest(); }, this.updateTotals));
            this.Items.Add(TestItemViewModel.Create("Get sock name for IPv6 address stream socket", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.GetSockNameWithIpv6StreamSocketTest(); }, this.updateTotals));
            this.Items.Add(TestItemViewModel.Create("Get sock name for IPv6 address datagram socket", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.GetSockNameWithIpv6DatagramSocketTest(); }, this.updateTotals));
            this.Items.Add(TestItemViewModel.Create("Get sock name for host name address stream socket", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.GetSockNameWithHostNameStreamSocketTest(); }, this.updateTotals));
            this.Items.Add(TestItemViewModel.Create("Get sock name for host name address datagram socket", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.GetSockNameWithHostNameDatagramSocketTest(); }, this.updateTotals));
            
            this.Items.Add(TestItemViewModel.Create("Get host name", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.GetHostNameTest(); }, this.updateTotals));
            
            //this.Items.Add(TestItemViewModel.Create("Get best source with IPv4 address", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.GetBestSourceWithIpv4Test(); }, this.updateTotals));
            //this.Items.Add(TestItemViewModel.Create("Get best source with IPv6 address", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.GetBestSourceWithIpv6Test(); }, this.updateTotals));
            //this.Items.Add(TestItemViewModel.Create("Get best source with hostname address", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.GetBestSourceWithHostNameTest(); }, this.updateTotals));
            
            this.Items.Add(TestItemViewModel.Create("Get sock IP and port with IPv4 address", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.GetSockIpAndPortWithIpv4Test(); }, this.updateTotals));
            this.Items.Add(TestItemViewModel.Create("Get sock IP and port with IPv6 address", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.GetSockIpAndPortWithIpv6Test(); }, this.updateTotals));
            this.Items.Add(TestItemViewModel.Create("Get sock IP and port with host name address", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.GetSockIpAndPortWithHostNameTest(); }, this.updateTotals));
            
            this.Items.Add(TestItemViewModel.Create("Get peer name for IPv4 address stream socket", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.GetPeerNameWithIpv4StreamSocketTest(); }, this.updateTotals));
            this.Items.Add(TestItemViewModel.Create("Get peer name for IPv4 address datagram socket", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.GetPeerNameWithIpv4DatagramSocketTest(); }, this.updateTotals));
            this.Items.Add(TestItemViewModel.Create("Get peer name for IPv6 address stream socket", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.GetPeerNameWithIpv6StreamSocketTest(); }, this.updateTotals));
            this.Items.Add(TestItemViewModel.Create("Get peer name for IPv6 address datagram socket", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.GetPeerNameWithIpv6DatagramSocketTest(); }, this.updateTotals));
            this.Items.Add(TestItemViewModel.Create("Get peer name for host name address stream socket", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.GetPeerNameWithHostNameStreamSocketTest(); }, this.updateTotals));
            this.Items.Add(TestItemViewModel.Create("Get peer name for host name address datagram socket", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.GetPeerNameWithHostNameDatagramSocketTest(); }, this.updateTotals));
            
            //this.Items.Add(TestItemViewModel.Create("Bind stream socket", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.BindStreamSocketTest(); }, this.updateTotals));
            //this.Items.Add(TestItemViewModel.Create("Bind stream socket to unavailable address", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.BindStreamSocketToUnavailableAddressTest(); }, this.updateTotals));
            //this.Items.Add(TestItemViewModel.Create("Bind datagram socket", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.BindDatagramSocketTest(); }, this.updateTotals));
            //this.Items.Add(TestItemViewModel.Create("Accept stream socket", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.AcceptStreamSocketTest(); }, this.updateTotals));
            
            this.Items.Add(TestItemViewModel.Create("Send stream socket IPv4", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.SendStreamSocketWithIpv4Test(); }, this.updateTotals));
            this.Items.Add(TestItemViewModel.Create("Send datagram socket IPv4", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.SendToDatagramSocketWithIpv4Test(); }, this.updateTotals));
            this.Items.Add(TestItemViewModel.Create("Send stream socket IPv6", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.SendStreamSocketWithIpv6Test(); }, this.updateTotals));
            this.Items.Add(TestItemViewModel.Create("Send datagram socket IPv6", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.SendToDatagramSocketWithIpv6Test(); }, this.updateTotals));
            this.Items.Add(TestItemViewModel.Create("Winsock send stream socket IPv4", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.WSASendStreamSocketWithIpv4Test(); }, this.updateTotals));
            this.Items.Add(TestItemViewModel.Create("Winsock send datagram socket IPv4", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.WSASendToDatagramSocketWithIpv4Test(); }, this.updateTotals));
            this.Items.Add(TestItemViewModel.Create("Winsock send stream socket IPv6", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.WSASendStreamSocketWithIpv6Test(); }, this.updateTotals));
            this.Items.Add(TestItemViewModel.Create("Winsock send datagram socket IPv6", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.WSASendToDatagramSocketWithIpv6Test(); }, this.updateTotals));

            this.Items.Add(TestItemViewModel.Create("Read stream socket IPv4", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.RecvStreamSocketWithIpv4Test(); }, this.updateTotals));
            this.Items.Add(TestItemViewModel.Create("Read datagram socket IPv4", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.RecvFromDatagramSocketWithIpv4Test(); }, this.updateTotals));
            this.Items.Add(TestItemViewModel.Create("Read stream socket IPv6", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.RecvStreamSocketWithIpv6Test(); }, this.updateTotals));
            this.Items.Add(TestItemViewModel.Create("Read datagram socket IPv6", Colors.Gray, "Not run", dispatcher, this.updateTotals, () => { return this.utility.RecvFromDatagramSocketWithIpv6Test(); }, this.updateTotals));

            this.utility = new WinRTSock_RuntimeComponents_Test.WinRTSockTests();
            this.updateTotals();
        }

        private void updateTotals()
        {
            int totalCount = this.Items.Count;
            int succeededCount = this.Items.ToList().Where((x) => x.Result.HasValue && x.Result.Value).Count();
            int failedCount = this.Items.ToList().Where((x) => x.Result.HasValue && !x.Result.Value).Count();
            var color = totalCount == succeededCount ? Colors.Green : Colors.Red;
            if (succeededCount + failedCount < totalCount)
                color = Colors.Yellow;
            if (succeededCount + failedCount == 0)
                color = Colors.Gray;
            this.TestSuiteResultIndicator = new SolidColorBrush(color);
            this.TotalTestCount = totalCount;
            this.SucceededTestCount = succeededCount;
            this.FailedTestCount = failedCount;
        }
        public async void RunAllTests()
        {
            foreach (var item in this.Items)
            {
                item.Reset();
            }
            this.updateTotals();
            foreach (var item in this.Items)
            {
                await item.RunTest();
                this.updateTotals();
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
